package cn.kgc.vue.shiro;

import cn.hutool.crypto.digest.DigestUtil;
import cn.kgc.vue.entity.Permission;
import cn.kgc.vue.entity.RolePers;
import cn.kgc.vue.entity.UserRole;
import cn.kgc.vue.mapper.PermissionMapper;
import cn.kgc.vue.mapper.RolePersMapper;
import cn.kgc.vue.mapper.UserRoleMapper;
import cn.kgc.vue.utils.IpUtil;
import cn.kgc.vue.utils.JWTUtil;
import com.auth0.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.http.HttpRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class CustomerRealm extends AuthorizingRealm {

    private static final Logger log = LoggerFactory.getLogger(CustomerRealm.class);
    @Resource
    private JWTUtil jwtUtil;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RolePersMapper rolePersMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private PermissionMapper permissionMapper;

    //判断当前是否支持传入的token类型
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof  JWTToken;

    }
    /**
     * 获取授权信息
     * @param principals 当前用户的身份信息
     * @return 授权信息（包括角色和权限），当前实现返回 null
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Integer uid = (Integer) principals.getPrimaryPrincipal();
        // 1. 根据用户id  查询角色id  user_role
        LambdaQueryWrapper<UserRole> userRoleLambda = new QueryWrapper<UserRole>().lambda();
        userRoleLambda.eq(UserRole::getUserId,uid);

        List<Integer> rids = userRoleMapper.selectList(userRoleLambda).stream().map(userRole -> userRole.getRoleId())
                .collect(Collectors.toList());

        // 2. 根据角色id  查询权限id   role_permission
        LambdaQueryWrapper<RolePers> rolePersLambda = new QueryWrapper<RolePers>().lambda();
        rolePersLambda.in(RolePers::getRoleId,rids);
        Set<Integer> pIds = rolePersMapper.selectList(rolePersLambda).stream()
                .map(RolePers::getPerId)
                .collect(Collectors.toSet());
        // 3. 根据权限id  查询权限字符串
        LambdaQueryWrapper<Permission> permissionLambda = new QueryWrapper<Permission>().lambda();
        permissionLambda.in(Permission::getId,pIds)
                .eq(Permission::getIsMenu,2);
        List<String> permissions = permissionMapper.selectList(permissionLambda)
                .stream().map(Permission::getPermission)
                .collect(Collectors.toList());

        // 4.将权限字符创封装 返回
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(permissions);

        return simpleAuthorizationInfo;
    }

    /**
     * 获取认证信息
     * @param token 包含用户凭证的令牌
     * @return 认证信息，当前实现返回 null
     * @throws AuthenticationException 如果获取认证信息失败
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 此处应添加验证用户凭证的逻辑
        JWTToken jwtToken= (JWTToken) token;
        String tokenPrincipal=(String)jwtToken.getPrincipal();
        HttpServletRequest request = (HttpServletRequest) jwtToken.getRequest();

        //校验token
        jwtUtil.verify(tokenPrincipal);

        //token 和  ip是不是一样的
       String md5Hex= DigestUtil.md5Hex(tokenPrincipal);
       String redisIP=stringRedisTemplate.opsForValue().get(md5Hex);
       String md5Hex1= "4";


       //
        String s1 = (String) jwtToken.getS1();
        String s = stringRedisTemplate.opsForValue().get(md5Hex1);
        System.out.println("ssssssssssssssssssssssss"+s);
        System.out.println("--------------"+s1);
        if (!ObjectUtils.isNull(s1)){
            if (!s1.equals(s)){
                throw new RuntimeException("有人登录了 快改密码");
            }
        }
        //如果这个s和s1不一样 即为 另一个客户端登录

        //比较当前请求的ip和redisIP是否相同 不同则token调用
       String ip= IpUtil.getIp(request);
       if (!ip.equals(redisIP)){
           throw new RuntimeException("token非法,请重新认证");
       }
       //解析 token  uid
        Map<String, Object> claims = jwtUtil.getClaims(tokenPrincipal);
        Object uid =  claims.get("uid");

        //用户合法
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(uid, jwtToken.getCredentials(), this.getName());


        return simpleAuthenticationInfo;
    }
}
